package com.mi.system.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mi.common.core.constant.enums.RoleEnum;
import com.mi.common.core.util.TreeUtils;
import com.mi.system.dto.request.MenuRequestDTO;
import com.mi.system.entity.Menu;
import com.mi.system.mapper.MenuMapper;
import com.mi.system.vo.MenuVO;
import com.mi.system.vo.RoleVO;
import com.mi.system.vo.UserVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Menu service
 *
 * @author jin_huaquan
 * @version 1.0
 * @date 2021/11/1 14:01
 */
@Service
@RequiredArgsConstructor
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    private final UserService userService;

    @Override
    public List<MenuVO> getMenuTree() {
        List<MenuVO> menus = baseMapper.selectAll();

        return TreeUtils.build(menus, TreeUtils.DEFAULT_PARENT_ID);
    }

    @Override
    public List<MenuVO> getUserMenuTree() {
        UserVO user = userService.getCurrentUser();

        boolean admin = user.getRoles().stream()
                .anyMatch(role -> Objects.equals(role.getRoleCode(), RoleEnum.ADMIN.getCode()));
        if (admin) {
            return getMenuTree();
        }

        List<Long> roleIds = user.getRoles()
                .stream()
                .map(RoleVO::getId)
                .collect(Collectors.toList());

        List<MenuVO> menus = baseMapper.selectByRoleIdIn(roleIds);

        return TreeUtils.build(menus, TreeUtils.DEFAULT_PARENT_ID);
    }


    @Override
    @Transactional(rollbackFor = TransactionException.class)
    public boolean saveMenu(MenuRequestDTO request) {
        Assert.isFalse(existsByParentIdAndName(request.getParentId(), request.getName()), "已存在同名的菜单");

        Menu menu = new Menu();

        BeanUtil.copyProperties(request, menu);

        return this.save(menu);
    }

    @Override
    @Transactional(rollbackFor = TransactionException.class)
    public boolean updateMenu(Long id, MenuRequestDTO request) {
        Menu menu = baseMapper.selectById(id);
        Assert.notNull(menu, "未找到对应的菜单");

        if (!Objects.equals(request.getName(), menu.getName())) {
            Assert.isFalse(existsByParentIdAndName(request.getParentId(), request.getName()), "已存在同名的菜单");
        }

        BeanUtil.copyProperties(request, menu);

        return this.updateById(menu);
    }

    @Override
    @Transactional(rollbackFor = TransactionException.class)
    public Menu removeMenu(Long id) {
        Menu menu = baseMapper.selectById(id);
        Assert.notNull(menu, "未找到对应的菜单");

        baseMapper.deleteById(menu);

        return menu;
    }

    /**
     * whether menu exists with parent id and name
     *
     * @param parentId parent menu id
     * @param name     menu name
     * @return whether exists
     */
    private boolean existsByParentIdAndName(Long parentId, String name) {
        return baseMapper.selectCount(Wrappers.<Menu>lambdaQuery()
                .eq(Menu::getParentId, parentId)
                .eq(Menu::getName, name)) > 0;
    }
}
